home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / vidhrdw / atarisy1.c < prev    next >
C/C++ Source or Header  |  2000-05-18  |  27KB  |  1,007 lines

  1. /***************************************************************************
  2.  
  3.     Atari System 1 hardware
  4.  
  5. ****************************************************************************/
  6.  
  7.  
  8. #include "driver.h"
  9. #include "machine/atarigen.h"
  10. #include "vidhrdw/generic.h"
  11.  
  12. #define XCHARS 42
  13. #define YCHARS 30
  14.  
  15. #define XDIM (XCHARS*8)
  16. #define YDIM (YCHARS*8)
  17.  
  18.  
  19.  
  20. /*************************************
  21.  *
  22.  *    Constants
  23.  *
  24.  *************************************/
  25.  
  26. /* the color and remap PROMs are mapped as follows */
  27. #define PROM1_BANK_4            0x80        /* active low */
  28. #define PROM1_BANK_3            0x40        /* active low */
  29. #define PROM1_BANK_2            0x20        /* active low */
  30. #define PROM1_BANK_1            0x10        /* active low */
  31. #define PROM1_OFFSET_MASK        0x0f        /* postive logic */
  32.  
  33. #define PROM2_BANK_6_OR_7        0x80        /* active low */
  34. #define PROM2_BANK_5            0x40        /* active low */
  35. #define PROM2_PLANE_5_ENABLE    0x20        /* active high */
  36. #define PROM2_PLANE_4_ENABLE    0x10        /* active high */
  37. #define PROM2_PF_COLOR_MASK        0x0f        /* negative logic */
  38. #define PROM2_BANK_7            0x08        /* active low, plus PROM2_BANK_6_OR_7 low as well */
  39. #define PROM2_MO_COLOR_MASK        0x07        /* negative logic */
  40.  
  41. #define OVERRENDER_PRIORITY        1
  42. #define OVERRENDER_SPECIAL        2
  43.  
  44.  
  45.  
  46. /*************************************
  47.  *
  48.  *    Macros
  49.  *
  50.  *************************************/
  51.  
  52. /* these macros make accessing the indirection table easier, plus this is how the data
  53.    is stored for the pfmapped array */
  54. #define PACK_LOOKUP_DATA(bank,color,offset,bpp) \
  55.         (((((bpp) - 4) & 7) << 24) | \
  56.          (((color) & 255) << 16) | \
  57.          (((bank) & 15) << 12) | \
  58.          (((offset) & 15) << 8))
  59.  
  60. #define LOOKUP_BPP(data)            (((data) >> 24) & 7)
  61. #define LOOKUP_COLOR(data)             (((data) >> 16) & 0xff)
  62. #define LOOKUP_GFX(data)             (((data) >> 12) & 15)
  63. #define LOOKUP_CODE(data)             ((data) & 0x0fff)
  64.  
  65.  
  66.  
  67. /*************************************
  68.  *
  69.  *    Structures
  70.  *
  71.  *************************************/
  72.  
  73. struct pf_overrender_data
  74. {
  75.     struct osd_bitmap *bitmap;
  76.     int type;
  77. };
  78.  
  79.  
  80.  
  81. /*************************************
  82.  *
  83.  *    Globals we own
  84.  *
  85.  *************************************/
  86.  
  87. UINT8 *atarisys1_bankselect;
  88. UINT8 *atarisys1_prioritycolor;
  89.  
  90.  
  91.  
  92. /*************************************
  93.  *
  94.  *    Statics
  95.  *
  96.  *************************************/
  97.  
  98. /* playfield parameters */
  99. static struct atarigen_pf_state pf_state;
  100. static UINT16 priority_pens;
  101.  
  102. /* indirection tables */
  103. static UINT32 pf_lookup[256];
  104. static UINT32 mo_lookup[256];
  105.  
  106. /* INT3 tracking */
  107. static void *int3_timer[YDIM];
  108. static void *int3off_timer;
  109.  
  110. /* graphics bank tracking */
  111. static UINT8 bank_gfx[3][8];
  112. static unsigned int *pen_usage[MAX_GFX_ELEMENTS];
  113.  
  114. /* basic form of a graphics bank */
  115. static struct GfxLayout objlayout =
  116. {
  117.     8,8,    /* 8*8 sprites */
  118.     4096,    /* 4096 of them */
  119.     6,        /* 6 bits per pixel */
  120.     { 5*8*0x08000, 4*8*0x08000, 3*8*0x08000, 2*8*0x08000, 1*8*0x08000, 0*8*0x08000 },
  121.     { 0, 1, 2, 3, 4, 5, 6, 7 },
  122.     { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
  123.     8*8        /* every sprite takes 8 consecutive bytes */
  124. };
  125.  
  126.  
  127.  
  128. /*************************************
  129.  *
  130.  *    Prototypes
  131.  *
  132.  *************************************/
  133.  
  134. static const UINT8 *update_palette(void);
  135.  
  136. static void pf_color_callback(const struct rectangle *clip, const struct rectangle *tiles, const struct atarigen_pf_state *state, void *data);
  137. static void pf_render_callback(const struct rectangle *clip, const struct rectangle *tiles, const struct atarigen_pf_state *state, void *data);
  138. static void pf_overrender_callback(const struct rectangle *clip, const struct rectangle *tiles, const struct atarigen_pf_state *state, void *data);
  139.  
  140. static void mo_color_callback(const UINT16 *data, const struct rectangle *clip, void *param);
  141. static void mo_render_callback(const UINT16 *data, const struct rectangle *clip, void *param);
  142.  
  143. static int decode_gfx(void);
  144. static int get_bank(UINT8 prom1, UINT8 prom2, int bpp);
  145.  
  146. void atarisys1_scanline_update(int scanline);
  147.  
  148.  
  149.  
  150. /*************************************
  151.  *
  152.  *    Generic video system start
  153.  *
  154.  *************************************/
  155.  
  156. int atarisys1_vh_start(void)
  157. {
  158.     static struct atarigen_mo_desc mo_desc =
  159.     {
  160.         64,                  /* maximum number of MO's */
  161.         2,                   /* number of bytes per MO entry */
  162.         0x80,                /* number of bytes between MO words */
  163.         1,                   /* ignore an entry if this word == 0xffff */
  164.         3, 0, 0x3f,          /* link = (data[linkword] >> linkshift) & linkmask */
  165.         0                    /* render in reverse link order */
  166.     };
  167.  
  168.     static struct atarigen_pf_desc pf_desc =
  169.     {
  170.         8, 8,                /* width/height of each tile */
  171.         64, 64                /* number of tiles in each direction */
  172.     };
  173.  
  174.     int i, e;
  175.  
  176.     /* first decode the graphics */
  177.     if (decode_gfx())
  178.         return 1;
  179.  
  180.     /* reset the statics */
  181.     memset(&pf_state, 0, sizeof(pf_state));
  182.     memset(int3_timer, 0, sizeof(int3_timer));
  183.  
  184.     /* initialize the pen usage array */
  185.     for (e = 0; e < MAX_GFX_ELEMENTS; e++)
  186.         if (Machine->gfx[e])
  187.         {
  188.             pen_usage[e] = Machine->gfx[e]->pen_usage;
  189.  
  190.             /* if this element has 6bpp data, create a special new usage array for it */
  191.             if (Machine->gfx[e]->color_granularity == 64)
  192.             {
  193.                 const struct GfxElement *gfx = Machine->gfx[e];
  194.  
  195.                 /* allocate storage */
  196.                 pen_usage[e] = malloc(gfx->total_elements * 2 * sizeof(int));
  197.                 if (pen_usage[e])
  198.                 {
  199.                     unsigned int *entry;
  200.                     int x, y;
  201.  
  202.                     /* scan each entry, marking which pens are used */
  203.                     memset(pen_usage[e], 0, gfx->total_elements * 2 * sizeof(int));
  204.                     for (i = 0, entry = pen_usage[e]; i < gfx->total_elements; i++, entry += 2)
  205.                     {
  206.                         UINT8 *dp = gfx->gfxdata + i * gfx->char_modulo;
  207.                         for (y = 0; y < gfx->height; y++)
  208.                         {
  209.                             for (x = 0; x < gfx->width; x++)
  210.                             {
  211.                                 int color = dp[x];
  212.                                 entry[(color >> 5) & 1] |= 1 << (color & 31);
  213.                             }
  214.                             dp += gfx->line_modulo;
  215.                         }
  216.                     }
  217.                 }
  218.             }
  219.         }
  220.  
  221.     /* initialize the playfield */
  222.     if (atarigen_pf_init(&pf_desc))
  223.         return 1;
  224.  
  225.     /* initialize the motion objects */
  226.     if (atarigen_mo_init(&mo_desc))
  227.     {
  228.         atarigen_pf_free();
  229.         return 1;
  230.     }
  231.  
  232.     return 0;
  233. }
  234.  
  235.  
  236.  
  237. /*************************************
  238.  *
  239.  *    Video system shutdown
  240.  *
  241.  *************************************/
  242.  
  243. void atarisys1_vh_stop(void)
  244. {
  245.     int i;
  246.  
  247.     /* free any extra pen usage */
  248.     for (i = 0; i < MAX_GFX_ELEMENTS; i++)
  249.     {
  250.         if (pen_usage[i] && Machine->gfx[i] && pen_usage[i] != Machine->gfx[i]->pen_usage)
  251.             free(pen_usage[i]);
  252.         pen_usage[i] = 0;
  253.     }
  254.  
  255.     atarigen_pf_free();
  256.     atarigen_mo_free();
  257. }
  258.  
  259.  
  260.  
  261. /*************************************
  262.  *
  263.  *    Graphics bank selection
  264.  *
  265.  *************************************/
  266.  
  267. WRITE_HANDLER( atarisys1_bankselect_w )
  268. {
  269.     int oldword = READ_WORD(&atarisys1_bankselect[offset]);
  270.     int newword = COMBINE_WORD(oldword, data);
  271.     int scanline = cpu_getscanline();
  272.     int diff = oldword ^ newword;
  273.  
  274.     /* update memory */
  275.     WRITE_WORD(&atarisys1_bankselect[offset], newword);
  276.  
  277.     /* sound CPU reset */
  278.     if (diff & 0x0080)
  279.     {
  280.         cpu_set_reset_line(1, (newword & 0x0080) ? CLEAR_LINE : ASSERT_LINE);
  281.         if (!(newword & 0x0080)) atarigen_sound_reset();
  282.     }
  283.  
  284.     /* motion object bank select */
  285.     atarisys1_scanline_update(scanline);
  286.  
  287.     /* playfield bank select */
  288.     if (diff & 0x04)
  289.     {
  290.         pf_state.param[0] = (newword & 0x04) ? 0x80 : 0x00;
  291.         atarigen_pf_update(&pf_state, cpu_getscanline() + 1);
  292.     }
  293. }
  294.  
  295.  
  296.  
  297. /*************************************
  298.  *
  299.  *    Playfield horizontal scroll
  300.  *
  301.  *************************************/
  302.  
  303. WRITE_HANDLER( atarisys1_hscroll_w )
  304. {
  305.     int oldword = READ_WORD(&atarigen_hscroll[offset]);
  306.     int newword = COMBINE_WORD(oldword, data);
  307.     WRITE_WORD(&atarigen_hscroll[offset], newword);
  308.  
  309.     /* set the new scroll value and update the playfield status */
  310.     pf_state.hscroll = newword & 0x1ff;
  311.     atarigen_pf_update(&pf_state, cpu_getscanline() + 1);
  312. }
  313.  
  314.  
  315.  
  316. /*************************************
  317.  *
  318.  *    Playfield vertical scroll
  319.  *
  320.  *************************************/
  321.  
  322. WRITE_HANDLER( atarisys1_vscroll_w )
  323. {
  324.     int scanline = cpu_getscanline() + 1;
  325.  
  326.     int oldword = READ_WORD(&atarigen_vscroll[offset]);
  327.     int newword = COMBINE_WORD(oldword, data);
  328.     WRITE_WORD(&atarigen_vscroll[offset], newword);
  329.  
  330.     /* because this latches a new value into the scroll base,
  331.        we need to adjust for the scanline */
  332.     pf_state.vscroll = newword & 0x1ff;
  333.     if (scanline < YDIM) pf_state.vscroll -= scanline;
  334.     atarigen_pf_update(&pf_state, scanline);
  335. }
  336.  
  337.  
  338.  
  339. /*************************************
  340.  *
  341.  *    Playfield RAM write handler
  342.  *
  343.  *************************************/
  344.  
  345. WRITE_HANDLER( atarisys1_playfieldram_w )
  346. {
  347.     int oldword = READ_WORD(&atarigen_playfieldram[offset]);
  348.     int newword = COMBINE_WORD(oldword, data);
  349.  
  350.     if (oldword != newword)
  351.     {
  352.         WRITE_WORD(&atarigen_playfieldram[offset], newword);
  353.         atarigen_pf_dirty[offset / 2] = 0xff;
  354.     }
  355. }
  356.  
  357.  
  358.  
  359. /*************************************
  360.  *
  361.  *    Sprite RAM write handler
  362.  *
  363.  *************************************/
  364.  
  365. WRITE_HANDLER( atarisys1_spriteram_w )
  366. {
  367.     int oldword = READ_WORD(&atarigen_spriteram[offset]);
  368.     int newword = COMBINE_WORD(oldword, data);
  369.  
  370.     if (oldword != newword)
  371.     {
  372.         WRITE_WORD(&atarigen_spriteram[offset], newword);
  373.  
  374.         /* if modifying a timer, beware */
  375.         if (((offset & 0x180) == 0x000 && READ_WORD(&atarigen_spriteram[offset | 0x080]) == 0xffff) ||
  376.             ((offset & 0x180) == 0x080 && newword == 0xffff))
  377.         {
  378.             /* if the timer is in the active bank, update the display list */
  379.             if ((offset >> 9) == ((READ_WORD(&atarisys1_bankselect[0]) >> 3) & 7))
  380.             {
  381.                 logerror("Caught timer mod!\n");
  382.                 atarisys1_scanline_update(cpu_getscanline());
  383.             }
  384.         }
  385.     }
  386. }
  387.  
  388.  
  389.  
  390. /*************************************
  391.  *
  392.  *    MO interrupt handlers
  393.  *
  394.  *************************************/
  395.  
  396. static void int3off_callback(int param)
  397. {
  398.     /* clear the state */
  399.     atarigen_scanline_int_ack_w(0, 0);
  400.  
  401.     /* make this timer go away */
  402.     int3off_timer = 0;
  403. }
  404.  
  405.  
  406. void atarisys1_int3_callback(int param)
  407. {
  408.     /* update the state */
  409.     atarigen_scanline_int_gen();
  410.  
  411.     /* set a timer to turn it off */
  412.     if (int3off_timer)
  413.         timer_remove(int3off_timer);
  414.     int3off_timer = timer_set(cpu_getscanlineperiod(), 0, int3off_callback);
  415.  
  416.     /* set ourselves up to go off next frame */
  417.     int3_timer[param] = timer_set(TIME_IN_HZ(Machine->drv->frames_per_second), param, atarisys1_int3_callback);
  418. }
  419.  
  420.  
  421.  
  422. /*************************************
  423.  *
  424.  *    MO interrupt state read
  425.  *
  426.  *************************************/
  427.  
  428. READ_HANDLER( atarisys1_int3state_r )
  429. {
  430.     return atarigen_scanline_int_state ? 0x0080 : 0x0000;
  431. }
  432.  
  433.  
  434.  
  435. /*************************************
  436.  *
  437.  *    Periodic MO updater
  438.  *
  439.  *************************************/
  440.  
  441. void atarisys1_scanline_update(int scanline)
  442. {
  443.     int bank = ((READ_WORD(&atarisys1_bankselect[0]) >> 3) & 7) * 0x200;
  444.     UINT8 *base = &atarigen_spriteram[bank];
  445.     UINT8 spritevisit[64];
  446.     UINT8 timer[YDIM];
  447.     int link = 0;
  448.     int i;
  449.  
  450.     /* only process if we're still onscreen */
  451.     if (scanline < YDIM)
  452.     {
  453.         /* generic update first */
  454.         if (!scanline)
  455.             atarigen_mo_update(base, 0, 0);
  456.         else
  457.             atarigen_mo_update(base, 0, scanline + 1);
  458.     }
  459.  
  460.     /* visit all the sprites and look for timers */
  461.     memset(spritevisit, 0, sizeof(spritevisit));
  462.     memset(timer, 0, sizeof(timer));
  463.     while (!spritevisit[link])
  464.     {
  465.         int data2 = READ_WORD(&base[link * 2 + 0x080]);
  466.  
  467.         /* a codeure of 0xffff is really an interrupt - gross! */
  468.         if (data2 == 0xffff)
  469.         {
  470.             int data1 = READ_WORD(&base[link * 2 + 0x000]);
  471.             int vsize = (data1 & 15) + 1;
  472.             int ypos = (256 - (data1 >> 5) - vsize * 8) & 0x1ff;
  473.  
  474.             /* only generate timers on visible scanlines */
  475.             if (ypos < YDIM)
  476.                 timer[ypos] = 1;
  477.         }
  478.  
  479.         /* link to the next object */
  480.         spritevisit[link] = 1;
  481.         link = READ_WORD(&atarigen_spriteram[bank + link * 2 + 0x180]) & 0x3f;
  482.     }
  483.  
  484.     /* update our interrupt timers */
  485.     for (i = 0; i < YDIM; i++)
  486.     {
  487.         if (timer[i] && !int3_timer[i])
  488.             int3_timer[i] = timer_set(cpu_getscanlinetime(i), i, atarisys1_int3_callback);
  489.         else if (!timer[i] && int3_timer[i])
  490.         {
  491.             timer_remove(int3_timer[i]);
  492.             int3_timer[i] = 0;
  493.         }
  494.     }
  495. }
  496.  
  497.  
  498.  
  499. /*************************************
  500.  *
  501.  *    Main refresh
  502.  *
  503.  *************************************/
  504.  
  505. void atarisys1_vh_screenrefresh(struct osd_bitmap *bitmap,int full_refresh)
  506. {
  507.     int i;
  508.  
  509.     /* update the palette */
  510.     if (update_palette())
  511.         memset(atarigen_pf_dirty, 0xff, atarigen_playfieldram_size / 2);
  512.  
  513.     /* set up the all-transparent overrender palette */
  514.     for (i = 0; i < 16; i++)
  515.         atarigen_overrender_colortable[i] = palette_transparent_pen;
  516.  
  517.     /* render the playfield */
  518.     memset(atarigen_pf_visit, 0, 64*64);
  519.     atarigen_pf_process(pf_render_callback, bitmap, &Machine->drv->visible_area);
  520.  
  521.     /* render the motion objects */
  522.     priority_pens = READ_WORD(&atarisys1_prioritycolor[0]) & 0xff;
  523.     atarigen_mo_process(mo_render_callback, bitmap);
  524.  
  525.     /* redraw the alpha layer completely */
  526.     {
  527.         const struct GfxElement *gfx = Machine->gfx[0];
  528.         int sx, sy, offs;
  529.  
  530.         for (sy = 0; sy < YCHARS; sy++)
  531.             for (sx = 0, offs = sy*64; sx < XCHARS; sx++, offs++)
  532.             {
  533.                 int data = READ_WORD(&atarigen_alpharam[offs * 2]);
  534.                 int opaque = data & 0x2000;
  535.                 int code = data & 0x3ff;
  536.  
  537.                 if (code || opaque)
  538.                 {
  539.                     int color = (data >> 10) & 7;
  540.                     drawgfx(bitmap, gfx, code, color, 0, 0, 8 * sx, 8 * sy, 0,
  541.                             opaque ? TRANSPARENCY_NONE : TRANSPARENCY_PEN, 0);
  542.                 }
  543.             }
  544.     }
  545.  
  546.     /* update onscreen messages */
  547.     atarigen_update_messages();
  548. }
  549.  
  550.  
  551.  
  552. /*************************************
  553.  *
  554.  *    Palette management
  555.  *
  556.  *************************************/
  557.  
  558. static const UINT8 *update_palette(void)
  559. {
  560.     UINT16 al_map[8], pfmo_map[32];
  561.     int i, j;
  562.  
  563.     /* reset color tracking */
  564.     memset(pfmo_map, 0, sizeof(pfmo_map));
  565.     memset(al_map, 0, sizeof(al_map));
  566.     palette_init_used_colors();
  567.  
  568.     /* always remap the transluscent colors */
  569.     memset(&palette_used_colors[0x300], PALETTE_COLOR_USED, 16);
  570.  
  571.     /* update color usage for the playfield */
  572.     atarigen_pf_process(pf_color_callback, pfmo_map, &Machine->drv->visible_area);
  573.  
  574.     /* update color usage for the mo's */
  575.     atarigen_mo_process(mo_color_callback, pfmo_map);
  576.  
  577.     /* update color usage for the alphanumerics */
  578.     {
  579.         const unsigned int *usage = Machine->gfx[0]->pen_usage;
  580.         int sx, sy, offs;
  581.  
  582.         for (sy = 0; sy < YCHARS; sy++)
  583.             for (sx = 0, offs = sy * 64; sx < XCHARS; sx++, offs++)
  584.             {
  585.                 int data = READ_WORD(&atarigen_alpharam[offs * 2]);
  586.                 int color = (data >> 10) & 7;
  587.                 int code = data & 0x3ff;
  588.                 al_map[color] |= usage[code];
  589.             }
  590.     }
  591.  
  592.     /* determine the final playfield palette */
  593.     for (i = 16; i < 32; i++)
  594.     {
  595.         UINT16 used = pfmo_map[i];
  596.         if (used)
  597.             for (j = 0; j < 16; j++)
  598.                 if (used & (1 << j))
  599.                     palette_used_colors[0x100 + i * 16 + j] = PALETTE_COLOR_USED;
  600.     }
  601.  
  602.     /* determine the final motion object palette */
  603.     for (i = 0; i < 16; i++)
  604.     {
  605.         UINT16 used = pfmo_map[i];
  606.         if (used)
  607.         {
  608.             palette_used_colors[0x100 + i * 16] = PALETTE_COLOR_TRANSPARENT;
  609.             for (j = 1; j < 16; j++)
  610.                 if (used & (1 << j))
  611.                     palette_used_colors[0x100 + i * 16 + j] = PALETTE_COLOR_USED;
  612.         }
  613.     }
  614.  
  615.     /* determine the final alpha palette */
  616.     for (i = 0; i < 8; i++)
  617.     {
  618.         UINT16 used = al_map[i];
  619.         if (used)
  620.             for (j = 0; j < 4; j++)
  621.                 if (used & (1 << j))
  622.                     palette_used_colors[0x000 + i * 4 + j] = PALETTE_COLOR_USED;
  623.     }
  624.  
  625.     /* recalculate the palette */
  626.     return palette_recalc();
  627. }
  628.  
  629.  
  630.  
  631. /*************************************
  632.  *
  633.  *    Playfield palette
  634.  *
  635.  *************************************/
  636.  
  637. static void pf_color_callback(const struct rectangle *clip, const struct rectangle *tiles, const struct atarigen_pf_state *state, void *param)
  638. {
  639.     const UINT32 *lookup_table = &pf_lookup[state->param[0]];
  640.     UINT16 *colormap = param;
  641.     int x, y;
  642.  
  643.     /* standard loop over tiles */
  644.     for (y = tiles->min_y; y != tiles->max_y; y = (y + 1) & 63)
  645.         for (x = tiles->min_x; x != tiles->max_x; x = (x + 1) & 63)
  646.         {
  647.             int offs = y * 64 + x;
  648.             int data = READ_WORD(&atarigen_playfieldram[offs * 2]);
  649.             int lookup = lookup_table[(data >> 8) & 0x7f];
  650.             const unsigned int *usage = pen_usage[LOOKUP_GFX(lookup)];
  651.             int bpp = LOOKUP_BPP(lookup);
  652.             int code = LOOKUP_CODE(lookup) | (data & 0xff);
  653.             int color = LOOKUP_COLOR(lookup);
  654.             unsigned int bits;
  655.  
  656.             /* based on the depth, we need to tweak our pen mapping */
  657.             if (bpp == 0)
  658.                 colormap[color] |= usage[code];
  659.             else if (bpp == 1)
  660.             {
  661.                 bits = usage[code];
  662.                 colormap[color * 2] |= bits;
  663.                 colormap[color * 2 + 1] |= bits >> 16;
  664.             }
  665.             else
  666.             {
  667.                 bits = usage[code * 2];
  668.                 colormap[color * 4] |= bits;
  669.                 colormap[color * 4 + 1] |= bits >> 16;
  670.                 bits = usage[code * 2 + 1];
  671.                 colormap[color * 4 + 2] |= bits;
  672.                 colormap[color * 4 + 3] |= bits >> 16;
  673.             }
  674.  
  675.             /* also mark unvisited tiles dirty */
  676.             if (!atarigen_pf_visit[offs]) atarigen_pf_dirty[offs] = 0xff;
  677.         }
  678. }
  679.  
  680.  
  681.  
  682. /*************************************
  683.  *
  684.  *    Playfield rendering
  685.  *
  686.  *************************************/
  687.  
  688. static void pf_render_callback(const struct rectangle *clip, const struct rectangle *tiles, const struct atarigen_pf_state *state, void *param)
  689. {
  690.     int bank = state->param[0];
  691.     const UINT32 *lookup_table = &pf_lookup[bank];
  692.     struct osd_bitmap *bitmap = param;
  693.     int x, y;
  694.  
  695.     /* standard loop over tiles */
  696.     for (y = tiles->min_y; y != tiles->max_y; y = (y + 1) & 63)
  697.         for (x = tiles->min_x; x != tiles->max_x; x = (x + 1) & 63)
  698.         {
  699.             int offs = y * 64 + x;
  700.  
  701.             /* update only if dirty */
  702.             if (atarigen_pf_dirty[offs] != bank)
  703.             {
  704.                 int data = READ_WORD(&atarigen_playfieldram[offs * 2]);
  705.                 int lookup = lookup_table[(data >> 8) & 0x7f];
  706.                 const struct GfxElement *gfx = Machine->gfx[LOOKUP_GFX(lookup)];
  707.                 int code = LOOKUP_CODE(lookup) | (data & 0xff);
  708.                 int color = LOOKUP_COLOR(lookup);
  709.                 int hflip = data & 0x8000;
  710.  
  711.                 drawgfx(atarigen_pf_bitmap, gfx, code, color, hflip, 0, 8 * x, 8 * y, 0, TRANSPARENCY_NONE, 0);
  712.                 atarigen_pf_dirty[offs] = bank;
  713.             }
  714.  
  715.             /* track the tiles we've visited */
  716.             atarigen_pf_visit[offs] = 1;
  717.         }
  718.  
  719.     /* then blast the result */
  720.     x = -state->hscroll;
  721.     y = -state->vscroll;
  722.     copyscrollbitmap(bitmap, atarigen_pf_bitmap, 1, &x, 1, &y, clip, TRANSPARENCY_NONE, 0);
  723. }
  724.  
  725.  
  726.  
  727. /*************************************
  728.  *
  729.  *    Playfield overrendering
  730.  *
  731.  *************************************/
  732.  
  733. static void pf_overrender_callback(const struct rectangle *clip, const struct rectangle *tiles, const struct atarigen_pf_state *state, void *param)
  734. {
  735.     const UINT32 *lookup_table = &pf_lookup[state->param[0]];
  736.     const struct pf_overrender_data *overrender_data = param;
  737.     struct osd_bitmap *bitmap = overrender_data->bitmap;
  738.     int type = overrender_data->type;
  739.     int x, y;
  740.  
  741.     /* standard loop over tiles */
  742.     for (y = tiles->min_y; y != tiles->max_y; y = (y + 1) & 63)
  743.     {
  744.         int sy = (8 * y - state->vscroll) & 0x1ff;
  745.         if (sy >= YDIM) sy -= 0x200;
  746.  
  747.         for (x = tiles->min_x; x != tiles->max_x; x = (x + 1) & 63)
  748.         {
  749.             int offs = y * 64 + x;
  750.             int data = READ_WORD(&atarigen_playfieldram[offs * 2]);
  751.             int lookup = lookup_table[(data >> 8) & 0x7f];
  752.             const struct GfxElement *gfx = Machine->gfx[LOOKUP_GFX(lookup)];
  753.             int code = LOOKUP_CODE(lookup) | (data & 0xff);
  754.             int color = LOOKUP_COLOR(lookup);
  755.             int hflip = data & 0x8000;
  756.  
  757.             int sx = (8 * x - state->hscroll) & 0x1ff;
  758.             if (sx >= XDIM) sx -= 0x200;
  759.  
  760.             /* overrender based on the type */
  761.             if (type == OVERRENDER_PRIORITY)
  762.             {
  763.                 int bpp = LOOKUP_BPP(lookup);
  764.                 if (color == (16 >> bpp))
  765.                     drawgfx(bitmap, gfx, code, color, hflip, 0, sx, sy, clip, TRANSPARENCY_PENS, ~priority_pens);
  766.             }
  767.             else
  768.                 drawgfx(bitmap, gfx, code, color, hflip, 0, sx, sy, clip, TRANSPARENCY_PEN, 0);
  769.         }
  770.     }
  771. }
  772.  
  773.  
  774.  
  775. /*************************************
  776.  *
  777.  *    Motion object palette
  778.  *
  779.  *************************************/
  780.  
  781. static void mo_color_callback(const UINT16 *data, const struct rectangle *clip, void *param)
  782. {
  783.     UINT16 *colormap = param;
  784.     UINT16 temp = 0;
  785.     int i;
  786.  
  787.     UINT32 lookup = mo_lookup[data[1] >> 8];
  788.     const unsigned int *usage = pen_usage[LOOKUP_GFX(lookup)];
  789.     int code = LOOKUP_CODE(lookup) | (data[1] & 0xff);
  790.     int color = LOOKUP_COLOR(lookup);
  791.     int vsize = (data[0] & 0x000f) + 1;
  792.     int bpp = LOOKUP_BPP(lookup);
  793.  
  794.     if (bpp == 0)
  795.     {
  796.         for (i = 0; i < vsize; i++)
  797.             temp |= usage[code++];
  798.         colormap[color] |= temp;
  799.     }
  800.  
  801.     /* in theory we should support all 3 possible depths, but motion objects are all 4bpp */
  802. }
  803.  
  804.  
  805.  
  806. /*************************************
  807.  *
  808.  *    Motion object rendering
  809.  *
  810.  *************************************/
  811.  
  812. static void mo_render_callback(const UINT16 *data, const struct rectangle *clip, void *param)
  813. {
  814.     struct osd_bitmap *bitmap = param;
  815.     struct pf_overrender_data overrender_data;
  816.     struct rectangle pf_clip;
  817.  
  818.     /* extract data from the various words */
  819.     UINT32 lookup = mo_lookup[data[1] >> 8];
  820.     struct GfxElement *gfx = Machine->gfx[LOOKUP_GFX(lookup)];
  821.     int code = LOOKUP_CODE(lookup) | (data[1] & 0xff);
  822.     int color = LOOKUP_COLOR(lookup);
  823.     int xpos = data[2] >> 5;
  824.     int ypos = 256 - (data[0] >> 5);
  825.     int hflip = data[0] & 0x8000;
  826.     int vsize = (data[0] & 0x000f) + 1;
  827.     int priority = data[2] >> 15;
  828.  
  829.     /* adjust for height */
  830.     ypos -= vsize * 8;
  831.  
  832.     /* adjust the final coordinates */
  833.     xpos &= 0x1ff;
  834.     ypos &= 0x1ff;
  835.     if (xpos >= XDIM) xpos -= 0x200;
  836.     if (ypos >= YDIM) ypos -= 0x200;
  837.  
  838.     /* bail if X coordinate is out of range */
  839.     if (xpos <= -8 || xpos >= XDIM)
  840.         return;
  841.  
  842.     /* determine the bounding box */
  843.     atarigen_mo_compute_clip_8x8(pf_clip, xpos, ypos, 1, vsize, clip);
  844.  
  845.     /* standard priority case? */
  846.     if (!priority)
  847.     {
  848.         /* draw the motion object */
  849.         atarigen_mo_draw_8x8_strip(bitmap, gfx, code, color, hflip, 0, xpos, ypos, vsize, clip, TRANSPARENCY_PEN, 0);
  850.  
  851.         /* do we have a priority color active? */
  852.         if (priority_pens)
  853.         {
  854.             overrender_data.bitmap = bitmap;
  855.             overrender_data.type = OVERRENDER_PRIORITY;
  856.  
  857.             /* overrender the playfield */
  858.             atarigen_pf_process(pf_overrender_callback, &overrender_data, &pf_clip);
  859.         }
  860.     }
  861.  
  862.     /* high priority case? */
  863.     else
  864.     {
  865.         /* draw the sprite in bright pink on the real bitmap */
  866.         atarigen_mo_draw_transparent_8x8_strip(bitmap, gfx, code, hflip, 0, xpos, ypos, vsize, clip, TRANSPARENCY_PEN, 0);
  867.  
  868.         /* also draw the sprite normally on the temp bitmap */
  869.         atarigen_mo_draw_8x8_strip(atarigen_pf_overrender_bitmap, gfx, code, 0x20, hflip, 0, xpos, ypos, vsize, clip, TRANSPARENCY_NONE, 0);
  870.  
  871.         /* now redraw the playfield tiles over top of the sprite */
  872.         overrender_data.bitmap = atarigen_pf_overrender_bitmap;
  873.         overrender_data.type = OVERRENDER_SPECIAL;
  874.         atarigen_pf_process(pf_overrender_callback, &overrender_data, &pf_clip);
  875.  
  876.         /* finally, copy this chunk to the real bitmap */
  877.         copybitmap(bitmap, atarigen_pf_overrender_bitmap, 0, 0, 0, 0, &pf_clip, TRANSPARENCY_THROUGH, palette_transparent_pen);
  878.     }
  879. }
  880.  
  881.  
  882.  
  883. /*************************************
  884.  *
  885.  *    Graphics decoding
  886.  *
  887.  *************************************/
  888.  
  889. static int decode_gfx(void)
  890. {
  891.     UINT8 *prom1 = &memory_region(REGION_PROMS)[0x000];
  892.     UINT8 *prom2 = &memory_region(REGION_PROMS)[0x200];
  893.     int obj, i;
  894.  
  895.     /* reset the globals */
  896.     memset(&bank_gfx, 0, sizeof(bank_gfx));
  897.  
  898.     /* loop for two sets of objects */
  899.     for (obj = 0; obj < 2; obj++)
  900.     {
  901.         UINT32 *table = (obj == 0) ? pf_lookup : mo_lookup;
  902.  
  903.         /* loop for 256 objects in the set */
  904.         for (i = 0; i < 256; i++, prom1++, prom2++)
  905.         {
  906.             int bank, bpp, color, offset;
  907.  
  908.             /* determine the bpp */
  909.             bpp = 4;
  910.             if (*prom2 & PROM2_PLANE_4_ENABLE)
  911.             {
  912.                 bpp = 5;
  913.                 if (*prom2 & PROM2_PLANE_5_ENABLE)
  914.                     bpp = 6;
  915.             }
  916.  
  917.             /* determine the color */
  918.             if (obj == 0)
  919.                 color = (16 + (~*prom2 & PROM2_PF_COLOR_MASK)) >> (bpp - 4); /* playfield */
  920.             else
  921.                 color = (~*prom2 & PROM2_MO_COLOR_MASK) >> (bpp - 4);    /* motion objects (high bit ignored) */
  922.  
  923.             /* determine the offset */
  924.             offset = *prom1 & PROM1_OFFSET_MASK;
  925.  
  926.             /* determine the bank */
  927.             bank = get_bank(*prom1, *prom2, bpp);
  928.             if (bank < 0)
  929.                 return 1;
  930.  
  931.             /* set the value */
  932.             if (bank == 0)
  933.                 *table++ = 0;
  934.             else
  935.                 *table++ = PACK_LOOKUP_DATA(bank, color, offset, bpp);
  936.         }
  937.     }
  938.     return 0;
  939. }
  940.  
  941.  
  942.  
  943. /*************************************
  944.  *
  945.  *    Graphics bank mapping
  946.  *
  947.  *************************************/
  948.  
  949. static int get_bank(UINT8 prom1, UINT8 prom2, int bpp)
  950. {
  951.     int bank_offset[8] = { 0, 0x00000, 0x30000, 0x60000, 0x90000, 0xc0000, 0xe0000, 0x100000 };
  952.     int bank_index, i, gfx_index;
  953.  
  954.     /* determine the bank index */
  955.     if ((prom1 & PROM1_BANK_1) == 0)
  956.         bank_index = 1;
  957.     else if ((prom1 & PROM1_BANK_2) == 0)
  958.         bank_index = 2;
  959.     else if ((prom1 & PROM1_BANK_3) == 0)
  960.         bank_index = 3;
  961.     else if ((prom1 & PROM1_BANK_4) == 0)
  962.         bank_index = 4;
  963.     else if ((prom2 & PROM2_BANK_5) == 0)
  964.         bank_index = 5;
  965.     else if ((prom2 & PROM2_BANK_6_OR_7) == 0)
  966.     {
  967.         if ((prom2 & PROM2_BANK_7) == 0)
  968.             bank_index = 7;
  969.         else
  970.             bank_index = 6;
  971.     }
  972.     else
  973.         return 0;
  974.  
  975.     /* find the bank */
  976.     if (bank_gfx[bpp - 4][bank_index])
  977.         return bank_gfx[bpp - 4][bank_index];
  978.  
  979.     /* if the bank is out of range, call it 0 */
  980.     if (bank_offset[bank_index] >= memory_region_length(REGION_GFX2))
  981.         return 0;
  982.  
  983.     /* don't have one? let's make it ... first find any empty slot */
  984.     for (gfx_index = 0; gfx_index < MAX_GFX_ELEMENTS; gfx_index++)
  985.         if (Machine->gfx[gfx_index] == NULL)
  986.             break;
  987.     if (gfx_index == MAX_GFX_ELEMENTS)
  988.         return -1;
  989.  
  990.     /* tweak the structure for the number of bitplanes we have */
  991.     objlayout.planes = bpp;
  992.     for (i = 0; i < bpp; i++)
  993.         objlayout.planeoffset[i] = (bpp - i - 1) * 0x8000 * 8;
  994.  
  995.     /* decode the graphics */
  996.     Machine->gfx[gfx_index] = decodegfx(&memory_region(REGION_GFX2)[bank_offset[bank_index]], &objlayout);
  997.     if (!Machine->gfx[gfx_index])
  998.         return -1;
  999.  
  1000.     /* set the color information */
  1001.     Machine->gfx[gfx_index]->colortable = &Machine->remapped_colortable[256];
  1002.     Machine->gfx[gfx_index]->total_colors = 48 >> (bpp - 4);
  1003.  
  1004.     /* set the entry and return it */
  1005.     return bank_gfx[bpp - 4][bank_index] = gfx_index;
  1006. }
  1007.